package com.starblink.web.core

import android.webkit.JavascriptInterface
import com.apollographql.apollo3.api.Optional
import com.google.gson.*
import com.google.gson.reflect.TypeToken
import com.starblink.basic.apollo.ext.ApolloExt.findErrorCode
import com.starblink.android.basic.ext.runOnUIThread
import com.starblink.android.basic.ext.toJson
import com.starblink.android.basic.extension.navigationTo
import com.starblink.android.basic.network.base.BaseApiCodeAndUrl
import com.starblink.android.basic.network.base.SkGqlClient
import com.starblink.android.basic.sensorsdata.spm.GTrackerAssistUtils
import com.starblink.android.basic.user.UserDataCenter
import com.starblink.android.basic.util.bus.FlowBus
import com.starblink.android.basic.util.bus.FlowConst
import com.starblink.android.basic.util.bus.bean.CollectProductEvent
import com.starblink.basic.log.SKLogger
import com.starblink.basic.route.RoutePage
import com.starblink.basic.util.CheckUtil
import com.starblink.rocketreserver.*
import com.starblink.rocketreserver.type.SiteRequest
import com.starblink.web.bean.CollectItemBean
import com.starblink.web.bean.JsBridgeBean
import com.starblink.web.bean.JsBridgeReqBean
import com.starblink.android.basic.bridge.BridgeCommand
import com.starblink.android.basic.bridge.BridgeUtil
import kotlinx.coroutines.*
import java.net.URLDecoder
import kotlin.collections.HashMap

/**
 * 和JS交互方法
 * 03-28 by 五木
 */
class GuangJSBridge(mWebView: GuangWebView) {
    private val TAG = "GuangWebView"

    private var mWebView: GuangWebView =mWebView
    private var webJsI: GuangWebView.WebJsI?=null //交互接口
    private val gson=Gson()

    private var getProductCollectionStatus:String?=null //H5注册回调收藏状态回调
    private var getStoreFollowStatus:String?=null //H5注册回调订阅状态回调
    private var cancelStoresFollowStatus:String?=null //H5注册回调批量取消订阅回调
    private var bridgeCallback:String?=null //记录登录跳转后返回回调地址 登录状态回调
    fun setWebJsI(webJsI: GuangWebView.WebJsI?){
        this.webJsI=webJsI
    }

    /**
     * 桥接方式
     */
    @JavascriptInterface
    fun callHandler(json: String?) {
        SKLogger.d(TAG, "callHandler() json: $json")
        if (json.isNullOrEmpty()) {
            SKLogger.e(TAG, "callHandler json is null or empty")
            return
        }
        try {
            val reqData=gson.fromJson(json, JsBridgeMessage::class.java)
            val commandName=reqData.name
            val bridgeCallback:String?=reqData.callback
            val result:String?=commandName?.let {
                val paramStr=reqData.data?.let { if(reqData.data is String)reqData.data else reqData.data.toJson() }
                when(it){
                    "toast"->toast(paramStr)
                    "getAppToken"->getAppToken()
                    "tryBack"->tryBack(paramStr)
                    "closeH5"->closeH5()
                    "showTitleBar"->showTitleBar(paramStr)
                    "statusBarDark"->statusBarDark(paramStr)
                    "showLoadingAnim"->showLoadingAnim(paramStr)
                    "appShare"->appShare(paramStr)
                    "updateStoreSubscribeState"->updateStoreSubscribeState(paramStr)
                    "getAccountInfo"->getAccountInfo()
                    "clearCache"->clearCache()
                    "clearLocalStorage"->clearLocalStorage()
                    "clearCacheAndLocalStorage"->clearCacheAndLocalStorage()
                    "toAppNamed"->toAppNamed(paramStr,bridgeCallback)
                    "collectProductListV2"->collectProductListV2(paramStr,bridgeCallback)
                    "cancelCollectProductListV2"->cancelCollectProductListV2(paramStr,bridgeCallback)
                    "updateSite"->updateSite()
                    "accWebPages"->accWebPages(paramStr)
                    "addCollectedProductToBoard"->addCollectedProductToBoard(paramStr)
                    "easterActivityPopUp"->easterActivityPopUp(paramStr)
                    else -> {
                        SKLogger.e(TAG, "callHandler() no command $it")
                        JsBridgeBean<String>(error = "callHandler() no command $it").toJson()
                    }
                }

            }
            if(CheckUtil.isEmpty(result)){
                //没有结果不需要回调H5方法
                return
            }
            postBridgeCallback(bridgeCallback,result)

        } catch (e: JsonSyntaxException) {
            SKLogger.e(TAG, "callHandler() catch. json: $json ${e.message}")
            e.printStackTrace()
        }
    }

    //注册方法
    @JavascriptInterface
    fun registerHandler(json: String?){
        SKLogger.d(TAG, "registerHandler() json: $json")
        if (json.isNullOrEmpty()) {
            SKLogger.e(TAG, "registerHandler json is null or empty")
            return
        }
        try {
            val reqData = gson.fromJson(json, JsBridgeMessage::class.java)
            val commandName = reqData.name
            val bridgeCallback: String? = reqData.callback
            commandName?.let {
                when(it){
                    "getProductCollectionStatus"->getProductCollectionStatus=bridgeCallback
                    "getStoreFollowStatus"->getStoreFollowStatus=bridgeCallback
                    "cancelStoresFollowStatus"->cancelStoresFollowStatus=bridgeCallback
                }
            }
        }catch (e: JsonSyntaxException) {
            SKLogger.e(TAG, "registerHandler() catch. json: $json ${e.message}")
            e.printStackTrace()
        }
    }

    //原生Toast方法
    @JavascriptInterface
    fun toast(data:String?):String{
        runOnUIThread {
            com.starblink.android.basic.ext.toast(data)
        }
        return JsBridgeBean(data="done").toJson()
    }

    //获取登录token
    @JavascriptInterface
    fun getAppToken():String{
        return JsBridgeBean(data=mapOf("appToken" to UserDataCenter.getToken())).toJson()
    }

    //回退或退出web容器
    @JavascriptInterface
    fun tryBack(data:String?):String{
        //模拟点击物理返回键 返回键实现了回退相关方法
        var params:JsBridgeReqBean<Any>? = null
        if (!CheckUtil.isEmpty(data)) {
            params = gson.fromJson(data, object : TypeToken<JsBridgeReqBean<Any>>() {}.type)
        }
        webJsI?.let {
            if(params?.navPop == true) {
                it.closeH5()
            }else{
                it.tryBack()
            }
        }
        return JsBridgeBean(data="done").toJson()
    }

    //直接关闭当前H5容器
    @JavascriptInterface
    fun closeH5():String{
        webJsI?.closeH5()
        return JsBridgeBean(data="done").toJson()
    }

    //显示隐藏titleBar
    //true-显示 false-隐藏
    @JavascriptInterface
    fun showTitleBar(data: String?) :String{
        var params:JsBridgeReqBean<Any>? = null
        if (!CheckUtil.isEmpty(data)) {
            params = gson.fromJson(data, object : TypeToken<JsBridgeReqBean<Any>>() {}.type)
        }
        webJsI?.showTitleBar(params?.show)
        return JsBridgeBean(data=mapOf("titleBarStatus" to (params?.show==true))).toJson()
    }

    //设置状态栏深色主题或浅色主题
    //true-深色 false-浅色
    @JavascriptInterface
    fun statusBarDark(data: String?):String {
        var params:JsBridgeReqBean<Any>? = null
        if (!CheckUtil.isEmpty(data)) {
            params = gson.fromJson(data, object : TypeToken<JsBridgeReqBean<Any>>() {}.type)
        }
        webJsI?.setStatusBarColor(params?.dark)
        return JsBridgeBean(data=mapOf("statusBarDark" to (params?.dark==true))).toJson()
    }

    //是否显示loading
    //true-显示 false-隐藏
    @JavascriptInterface
    fun showLoadingAnim(data:String?):String{
        var params:JsBridgeReqBean<Any>? = null
        if (!CheckUtil.isEmpty(data)) {
            params = gson.fromJson(data, object : TypeToken<JsBridgeReqBean<Any>>() {}.type)
        }
        webJsI?.showLoadingAnim(params?.show)
        return JsBridgeBean(data=mapOf("showLoadingAnim" to (params?.show==true))).toJson()
    }

    //调用原生分享
    //shareType 分享类型 0-图片 1-视频 2-话题 3-用户hashtag
    //shareId 分享内容id
    @JavascriptInterface
    fun appShare(data:String?):String{
        var params:JsBridgeReqBean<Any>? = null
        if (!CheckUtil.isEmpty(data)) {
            params = gson.fromJson(data, object : TypeToken<JsBridgeReqBean<Any>>() {}.type)
        }
        webJsI?.appShare(params?.urlLink)
        return JsBridgeBean(data="success").toJson()
    }

    //刷新首页和店铺数据
    @JavascriptInterface
    fun updateStoreSubscribeState(data:String?):String{
        var params:JsBridgeReqBean<Any>? = null
        if (!CheckUtil.isEmpty(data)) {
            params = gson.fromJson(data, object : TypeToken<JsBridgeReqBean<Any>>() {}.type)
        }
        webJsI?.updateStoreSubscribeState(params?.storeId,params?.subOrNot)
        return JsBridgeBean(data="success").toJson()
    }

    //获取用户信息
    @JavascriptInterface
    fun getAccountInfo():String{
        return if (UserDataCenter.isLogin()) {
            JsBridgeBean(data=UserDataCenter.getAccountInfo()).toJson()
        }else{
            JsBridgeBean<String>(error = "user did not login").toJson()
        }
    }

    //清理H5缓存
    @JavascriptInterface
    fun clearCache():String{
        runOnUIThread {
            mWebView.clearCache(false) //清理缓存
        }
        return JsBridgeBean(data="cache cleared!").toJson()
    }
    @JavascriptInterface
    fun clearLocalStorage():String{
        runOnUIThread {
            mWebView.clearCache(true) //清理缓存
            mWebView.clearFormData()
        }
        return JsBridgeBean(data="local storage cleared!").toJson()
    }
    //清理H5缓存
    @JavascriptInterface
    fun clearCacheAndLocalStorage():String{
        runOnUIThread {
            mWebView.clearCache(true) //清理缓存
            mWebView.clearFormData()
        }
        return JsBridgeBean(data="cache and local storage cleared!").toJson()
    }

    //路由跳转
    //route 路由地址
    //parameters map以json格式传递
    @JavascriptInterface
    fun toAppNamed(data:String?):String{
        return toAppNamed(data,null)
    }

    //批量收藏操作
    @JavascriptInterface
    fun collectProductListV2(data:String?):String{
        return collectProductListV2(data,null)
    }
    //批量取消收藏操作
    @JavascriptInterface
    fun cancelCollectProductListV2(data:String?):String{
        return cancelCollectProductListV2(data,null)
    }

    //检查站点
    @JavascriptInterface
    fun updateSite():String{
        GlobalScope.launch {
            val response = SkGqlClient.skQuery(
                FetchSiteQuery(
                    param = SiteRequest()
                ),
                showDefaultLoading = true
            )
            response?.data?.fetchSite?.let {
                SKLogger.d("SKLogger","updateSite Call Success")
                runOnUIThread {
                    com.starblink.android.basic.ext.toast(it.toString())
                }
            }
        }
        return JsBridgeBean(data="updateSite:we go for it!").toJson()
    }

    //预加载H5列表页面
    @JavascriptInterface
    fun accWebPages(data:String?):String{
        var params:JsBridgeReqBean<Any>? = null
        if (!CheckUtil.isEmpty(data)) {
            params = gson.fromJson(data, object : TypeToken<JsBridgeReqBean<Any>>() {}.type)
        }
        webJsI?.accWebPages(params?.WebPages)
        return JsBridgeBean(data="urls acced").toJson()
    }

    // 添加已收藏的商品到心愿单
    private fun addCollectedProductToBoard(data:String?):String{
        var params:JsBridgeReqBean<Any>? = null
        if (!CheckUtil.isEmpty(data)) {
            params = gson.fromJson(data, object : TypeToken<JsBridgeReqBean<Any>>() {}.type)
        }
        params?.type?.let {
            webJsI?.addCollectedProductToBoard(params.productId,it,params.mainImg)
        }
        return JsBridgeBean(data="done").toJson()
    }

    //跳转路由
    fun toAppNamed(data:String?, bridgeCallback:String?):String{
        var params:JsBridgeReqBean<Any>? = null
        if (!CheckUtil.isEmpty(data)) {
            params = gson.fromJson(data, object : TypeToken<JsBridgeReqBean<Any>>() {}.type)
        }
        if(CheckUtil.isEmpty(params?.route)){
            return JsBridgeBean<String>(error="route not right!").toJson()
        }
        params?.route?.let { routeUrl ->

            //--start-- 补坑 转Uri后url参数会丢失&后的参数 以及兼容 外链不encode现状
            var url:String?=null
            if(routeUrl.contains("${RoutePage.Web.ARG_URL}=")){
                url=routeUrl.substring(routeUrl.indexOf("${RoutePage.Web.ARG_URL}="))
                url=url.substring(url.indexOf("=")+1)
                if(url.contains("?")){
                    //只有跳转链接中存在问号时特殊处理
                    params.route =routeUrl.replace("${RoutePage.Web.ARG_URL}=","targetUrl=")
                }else{
                    url=null
                }
            }
            //--end-- 补坑

            navigationTo(params.route){
                url?.let {
                    withString(RoutePage.Web.ARG_URL, URLDecoder.decode(it,"UTF-8"))
                }
            }
        }
        if(params?.off==true){
            //是否关闭前一个页面
            webJsI?.closeH5()
        }

        this.bridgeCallback=bridgeCallback //记录回调方法
        var route=params?.route?.let {
            when{
                it.contains("?")->it.substring(0,it.indexOf("?"))
                else ->it
            }
        }
        route=route?.let { RoutePage.getRealRouteStrFlutterTransNative(path=it) }
        return when(route){
            RoutePage.Login.SING_IN-> "" //登录页面等登录状态回调
            else -> JsBridgeBean(data="we go for it!").toJson()
        }
    }

    //收藏
    private fun collectProductListV2(data:String?, bridgeCallback:String?):String{
        var params:JsBridgeReqBean<List<CollectItemBean>>? = null
        if (!CheckUtil.isEmpty(data)) {
            params = gson.fromJson(data, object : TypeToken<JsBridgeReqBean<List<CollectItemBean>>>() {}.type)
        }
        params?.items?.let { it ->
            it.forEach { firstItemBean ->
                CoroutineScope(Dispatchers.IO).launch {
                    val response = SkGqlClient.skMutation(
                        CollectionProductMutation(//收藏
                            firstItemBean.id, firstItemBean.type!!, outOfferId = Optional.present(firstItemBean.outOfferId)
                        )
                    )
                    if (response?.data?.collectionProduct == true) {
                        SKLogger.d("SKLogger", "collectProductListV2 Call Success")
                        postBridgeCallback(
                            bridgeCallback,
                            JsBridgeBean(data = mapOf("collectProductListV2" to response?.data?.collectionProduct)).toJson()
                        )

                        //刷新app收藏状态
                        val collectProductEvent=CollectProductEvent(firstItemBean.id, true)
                        FlowBus.with<CollectProductEvent>(FlowConst.COLLECT_PRODUCT_EVENT)
                            .post(collectProductEvent)
                        //跨进程通信
                        BridgeUtil.sendFlowBus(FlowConst.COLLECT_PRODUCT_EVENT,collectProductEvent)

                    } else {
                        if (response?.findErrorCode(BaseApiCodeAndUrl.CODE_311015001)==true) {
                            webJsI?.addVWishlistFail()
                        }
                        postBridgeCallback(
                            bridgeCallback,
                            JsBridgeBean<String>(error = response.toString()).toJson()
                        )
                    }
                }
            }
        }
        return ""
    }

    //取消收藏
    private fun cancelCollectProductListV2(data:String?, bridgeCallback:String?):String{
        var params:JsBridgeReqBean<List<CollectItemBean>>? = null
        if (!CheckUtil.isEmpty(data)) {
            params = gson.fromJson(data, object : TypeToken<JsBridgeReqBean<List<CollectItemBean>>>() {}.type)
        }
        params?.items?.let { it ->
            it.forEach { firstItemBean ->
                CoroutineScope(Dispatchers.IO).launch {
                    val response = SkGqlClient.skMutation(
                        CancelCollectionProductMutation( //取消收藏
                            firstItemBean.id, firstItemBean.type!!
                        )
                    )
                    if (response?.data?.cancelCollectionProduct == true) {
                        SKLogger.d("SKLogger", "cancelCollectProductListV2 Call Success")
                        postBridgeCallback(
                            bridgeCallback,
                            JsBridgeBean(data = mapOf("cancelCollectProductListV2" to response?.data?.cancelCollectionProduct)).toJson()
                        )
                        //刷新app收藏状态
                        val collectProductEvent=CollectProductEvent(firstItemBean.id, false)
                        FlowBus.with<CollectProductEvent>(FlowConst.COLLECT_PRODUCT_EVENT)
                            .post(collectProductEvent)
                        //跨进程发送通知
                        BridgeUtil.sendFlowBus(FlowConst.COLLECT_PRODUCT_EVENT,collectProductEvent)
                    } else {
                        postBridgeCallback(
                            bridgeCallback,
                            JsBridgeBean<String>(error = response.toString()).toJson()
                        )
                    }
                }
            }
                //批量
//                if(!UserDataCenter.isLogin()){
//                    //未登录状态
//                    return JsBridgeBean<String>(error="user not login!").toJson()
//                }
//                var items = ArrayList<CollectItem>()
//                for (item in it) {
//                    var collectItem = CollectItem(
//                        item.id,
//                        Optional.present(item.type!!),
//                        Optional.present(item.outOfferId)
//                    )
//                    items.add(collectItem)
//                }
//                MainScope().launch {
//                    val response = SkGqlClient.skMutation(
//                        CancelCollectProductListV2Mutation(
//                            items = Optional.present(items)
//                        ),
//                        showDefaultLoading = true
//                    )
//                    if (response?.data?.cancelCollectProductListV2 == true) {
//                        SKLogger.d("SKLogger", "cancelCollectProductListV2 Call Success")
//                        postBridgeCallback(
//                            bridgeCallback,
//                            JsBridgeBean(data = response.data).toJson()
//                        )
//                    } else {
//                        postBridgeCallback(
//                            bridgeCallback,
//                            JsBridgeBean<String>(error = response.toString()).toJson()
//                        )
//                    }
//                }

        }
        return ""
    }
    //埋点spm与H5交换
    fun easterActivityPopUp(data:String?):String{
        var params:JsBridgeReqBean<Any>? = null
        if (!CheckUtil.isEmpty(data)) {
            params = gson.fromJson(data, object : TypeToken<JsBridgeReqBean<Any>>() {}.type)
        }

        var preSpm=GTrackerAssistUtils.previousEvent
        if(!CheckUtil.isEmpty(params?.preSpm)){
            GTrackerAssistUtils.previousEvent=params?.preSpm
            //跨进程切换Web进程站点
            BridgeUtil.sendCommonData(BridgeCommand.Common.previousEvent,GTrackerAssistUtils.previousEvent)
        }
        return JsBridgeBean(data=mapOf("preSpm" to preSpm)).toJson()
    }

    /**
     * 从登录页面回来通知H5登录状态
     * 从收藏或取消收藏回来刷新H5页面
     */
    fun onActivityResult(eventKey:String,result:String){
        when(eventKey){
            FlowConst.LOGIN_STATUS_CHANGE->{ //登录状态
                //登录页面回调
                if(!CheckUtil.isEmpty(bridgeCallback)){
                    postBridgeCallback(bridgeCallback,result)
                }
                bridgeCallback=null
            }
            FlowConst.COLLECT_PRODUCT_EVENT->{ //收藏状态
                if(!CheckUtil.isEmpty(getProductCollectionStatus)){
                    postBridgeCallback(getProductCollectionStatus,result)
                }
            }
            FlowConst.FOLLOW_STORE_EVENT->{ //订阅状态
                if(!CheckUtil.isEmpty(getStoreFollowStatus)){
                    postBridgeCallback(getStoreFollowStatus,result)
                }
            }
            FlowConst.REMOVE_STORE_EVENT->{ //批量取消订阅状态
                if(!CheckUtil.isEmpty(cancelStoresFollowStatus)){
                    postBridgeCallback(cancelStoresFollowStatus,result)
                }
            }
        }
    }

    /**
     * 桥接回调
     */
    private fun postBridgeCallback(key: String?, data: String?) {
        if(CheckUtil.isEmpty(key)){
            return
        }
        runOnUIThread {
            mWebView.evaluateJavascript("javascript:window.postBridgeCallback('$key','$data')") {}
        }
    }

    /**
     * 根据路由修改入参数类型
     *
     */
    private fun changeParamsType(route:String?,params:HashMap<String,Any>):HashMap<String,Any>{
        when(route){
            RoutePage.Web.PAGE_GLOBAL_H5->{
                if(params.containsKey("url")){
                    //H5跳转地址需要decode
                    params["url"]=URLDecoder.decode(params["url"].toString(),"UTF-8")
                }
            }
            RoutePage.Product.PAGE_LINK->{
                if(params.containsKey("subOrNot")){
                    params["subOrNot"]=(params["subOrNot"]=="1")
                }
                if(params.containsKey("type")){
                    params["type"]=params["type"].toString().toInt()
                }
                if(params.containsKey("collected")){
                    params["collected"]=params["collected"].toString().toInt()
                }
            }
            RoutePage.Store.PAGE_LINK->{
                if(params.containsKey("subOrNot")){
                    params["subOrNot"]=(params["subOrNot"]=="1")
                }
            }
        }
        return params
    }
    /**
     * 达人相关：
        /setting_instagram_oauth
        /creator_apply_access
        /creator_verify_email_page
        /creator_academy_page
        /publish_album
        活动营销相关：
        /home
        /h5?url=${encodeURIComponent(H5链接)
        /product_web_link
        /recommend_similar_products
        /stores_home_page
        /stores_link_page
        /stores_manage_page
        /user_login
     */
//    private fun changeRoute(route:String?):String{
//       return when(route){
//           "/h5"->RoutePage.Web.PAGE_GLOBAL_H5
//           "/search"->RoutePage.Search.PAGE_SEARCH
//           "/product_web_link"->RoutePage.Product.PAGE_LINK
//           "/recommend_similar_products"->RoutePage.Product.PAGE_DETAIL
//           "/stores_home_page"->RoutePage.Store.PAGE_HOME
//           "/stores_link_page"->RoutePage.Store.PAGE_LINK
//           "/stores_manage_page"->RoutePage.Store.PAGE_MANAGE
//           "/user_login"->RoutePage.Login.SING_IN
//           else -> ""
//        }
//    }
}